<script setup lang="ts">
import { computed, onMounted, ref, watch } from 'vue'
import { ALTITUDE, LENGTH, LengthUnit, LengthModel, lengthUnitName } from './length-util'
import { ifNaNOrNull } from './number-util'

type Props = {
  modelValue: number | undefined
  defaultUnit?: LengthUnit
  optional?: boolean
  min?: number
  max?: number
  disabled?: boolean
  type?: 'length' | 'altitude'
  invalidValue?: number
}

const props = withDefaults(defineProps<Props>(), {
  defaultUnit: LengthUnit.M,
  optional: false,
  disabled: false,
  invalidValue: LENGTH.NONE
})

const emits = defineEmits<{
  (e: 'update:modelValue', v: number): void
}>()

let lengthModel = LENGTH

function initLengthModel() {
  if (props.type && props.type === 'altitude') {
    lengthModel = ALTITUDE
  }
  if (props.invalidValue === LENGTH.NONE) {
    lengthModel = LENGTH
  } else if (props.invalidValue === ALTITUDE.NONE) {
    lengthModel = ALTITUDE
  } else {
    lengthModel = new LengthModel(props.invalidValue)
  }
}

let innerValue: number = 0
const str = ref<string | number>('')
let unit = LengthUnit.M
const unitName = ref<string>(lengthUnitName(LengthUnit.M))
const ph = computed(() => (props.optional ? '选填' : '必填'))
const ok = ref<boolean>(true)
function checkOk() {
  ok.value = doCheckOk()
}

function doCheckOk(): boolean {
  if (innerValue === undefined) {
    return props.optional
  }
  if (isNaN(innerValue)) {
    return false
  }
  if (lengthModel.invalid(innerValue)) {
    return props.optional
  }
  if (props.min != null && innerValue < props.min) {
    return false
  }
  if (props.max != null && innerValue > props.max) {
    return false
  }
  return true
}

function init() {
  initLengthModel()
  unit = props.defaultUnit
  unitName.value = lengthUnitName(unit)
  innerValue = ifNaNOrNull(props.modelValue, lengthModel.NONE)
  str.value = lengthModel.meter2str(innerValue, unit)
  checkOk()
}

function onInput() {
  if (typeof str.value === 'number') {
    innerValue = lengthModel.toMeter(str.value, unit)
  } else {
    innerValue = lengthModel.str2meter(str.value, unit)
  }
  checkOk()
  if (innerValue !== props.modelValue) {
    emits('update:modelValue', innerValue)
  }
}

function onModelValue() {
  const v = props.modelValue
  if (v === innerValue) {
    return
  }
  innerValue = ifNaNOrNull(v, lengthModel.NONE)
  str.value = lengthModel.meter2str(innerValue, unit)
  checkOk()
}

function updateUnit() {
  if (props.disabled) {
    return
  }
  if (unit === LengthUnit.M) {
    unit = LengthUnit.KM
  } else if (unit === LengthUnit.KM) {
    unit = LengthUnit.NM
  } else if (unit === LengthUnit.NM) {
    unit = LengthUnit.FT
  } else {
    unit = LengthUnit.M
  }
  unitName.value = lengthUnitName(unit)
  str.value = lengthModel.meter2str(innerValue, unit)
}

onMounted(() => init())
// watch(str, onInput)
watch(() => props.modelValue, onModelValue)
</script>
<template>
  <div class="length-input">
    <input
      v-model="str"
      @input="onInput"
      type="number"
      class="input"
      :class="{ 'is-danger': !ok }"
      :disabled="disabled"
      :placeholder="ph"
    />
    <span class="unit" :class="{ 'is-disabled': disabled }" @click="updateUnit">
      {{ unitName }}
    </span>
  </div>
</template>
